﻿using System;
using System.Collections.Generic;
using System.CodeDom.Compiler;

namespace SWF
{
    public class DefineFunction2 : IAction, IActionContainer
    {
        /*
            ActionDefineFunction2	UI8
            FunctionName			STRING
            NumParams				UI16
            RegisterCount			UI8
            PreloadParentFlag		UB[1]
            PreloadRootFlag			UB[1]
            SuppressSuperFlag		UB[1]
            PreloadSuperFlag		UB[1]
            SuppressArgumentsFlag	UB[1]
            PreloadArgumentsFlag	UB[1]
            SuppressThisFlag		UB[1]
            PreloadThisFlag			UB[1]
            Reserved				UB[7]
            PreloadGlobalFlag		UB[1]
            Parameters				REGISTERPARAM[NumParams]
            codeSize				UI16
            Register				UI8
            ParamName				STRING
         */
        public ActionKind ActionId { get { return ActionKind.DefineFunction; } }
        public uint Version { get { return 7; } }
        public uint Length
        {
            get
            {
                uint len = 3;

                len += 7; // flags etc

                len += (uint)FunctionName.Length + 1;

                foreach (KeyValuePair<uint, string> d in Parameters)
                {
                    len += (uint)d.Value.Length + 1 + 1;
                }

                return len;
            }
        }

        public uint StackPops { get { return 0; } }
        public uint StackPushes { get { return 0; } }
        public int StackChange { get { return 0; } }

        private uint codeSize;
        public uint CodeSize { get { return codeSize; } set { codeSize = value; } }
        private List<IAction> statements = new List<IAction>();
        public List<IAction> Statements { get { return statements; } }

        public string FunctionName;
        public uint RegisterCount;
        public PreloadFlags Preloads;

        //public bool PreloadParentFlag;
        //public bool PreloadRootFlag;
        public bool SuppressSuperFlag;
        //public bool PreloadSuperFlag;
        public bool SuppressArgumentsFlag;
        //public bool PreloadArgumentsFlag;
        public bool SuppressThisFlag;
        //public bool PreloadThisFlag;
        //public bool PreloadGlobalFlag;

        public Dictionary<uint, string> Parameters = new Dictionary<uint, string>(); //uint Register, string ParamName;

        private ConstantPool cp;

        public DefineFunction2(SwfReader r, ConstantPool cp)
        {
            this.cp = cp;
            FunctionName = r.GetString();
            uint paramCount = r.GetUI16();
            RegisterCount = (uint)r.GetByte();

            Preloads = PreloadFlags.Empty;
            if (r.GetBit())
            {
                Preloads |= PreloadFlags.Parent;
            }
            if (r.GetBit())
            {
                Preloads |= PreloadFlags.Root;
            }

            SuppressSuperFlag = r.GetBit();

            if (r.GetBit())
            {
                Preloads |= PreloadFlags.Super;
            }

            SuppressArgumentsFlag = r.GetBit();

            if (r.GetBit())
            {
                Preloads |= PreloadFlags.Arguments;
            }

            SuppressThisFlag = r.GetBit();

            if (r.GetBit())
            {
                Preloads |= PreloadFlags.This;
            }

            r.GetBits(7); // reserved

            if (r.GetBit())
            {
                Preloads |= PreloadFlags.Global;
            }

            for (int i = 0; i < paramCount; i++)
            {
                uint reg = r.GetByte();
                string name = r.GetString();
                Parameters.Add(reg, name);
            }
            CodeSize = r.GetUI16();
        }

        public void Execute(Runtime.Clip clip, Stack<object> stack, Dictionary<string, object> variables, List<string> constantPool, Dictionary<string, List<IAction>> functionmap)
        {
        }

        public static string PreloadFlagToString(PreloadFlags flag)
        {
            string result;
            switch (flag)
            {
                case PreloadFlags.This:
                    result = "this";
                    break;
                case PreloadFlags.Arguments:
                    result = "arguments";
                    break;
                case PreloadFlags.Super:
                    result = "super";
                    break;
                case PreloadFlags.Root:
                    result = "_root";
                    break;
                case PreloadFlags.Parent:
                    result = "_parent";
                    break;
                case PreloadFlags.Global:
                    result = "_global";
                    break;
                default:
                    result = "";
                    break;
            }
            return result;
        }
    }
}
